package com.yoki.cloud.common.protocol.radius.msg.packet.check.req;

import com.yoki.cloud.common.protocol.radius.attribute.attr.RadiusMsgAttr;
import com.yoki.cloud.common.protocol.radius.attribute.attr.check.*;
import com.yoki.cloud.common.protocol.radius.attribute.parser.RadiusMsgAttrParser;
import com.yoki.cloud.common.protocol.radius.exception.RadiusException;
import com.yoki.cloud.common.protocol.radius.msg.packet.ReqRadiusMsg;
import com.yoki.cloud.common.utils.encrypt.EncryptUtils;

import java.util.LinkedList;
import java.util.List;
import java.util.UUID;

/**
 * @author Sky$
 * @Description: TODO
 * @date 2018/1/12$ 9:28$
 */
public class AccessRequestMsg extends ReqRadiusMsg {

    public static final int PACKET_CODE = 1;

    /**
     * Passphrase Authentication Protocol
     */
    public static final String AUTH_PAP = "pap";

    /**
     * Challenged Handshake Authentication Protocol
     */
    public static final String AUTH_CHAP = "chap";

    public String authProtocol = AUTH_PAP;

    public UserNameAttr userNameAttr;
    public RadiusMsgAttr passwordAttr;

    /**
     * Returns the protocol used for encrypting the passphrase.
     *
     * @return AUTH_PAP or AUTH_CHAP
     */
    public String getAuthProtocol() {
        return authProtocol;
    }

    /**
     * Selects the protocol to use for encrypting the passphrase when
     * encoding this Radius packet.
     *
     * @param authProtocol AUTH_PAP or AUTH_CHAP
     */
    public void setAuthProtocol(String authProtocol) {
        if (authProtocol != null) {
            if (authProtocol.equalsIgnoreCase(AUTH_PAP) || authProtocol.equalsIgnoreCase(AUTH_CHAP)) {
                this.authProtocol = authProtocol.toLowerCase();
                return;
            }
        }
        throw new IllegalArgumentException("Auth protocol must be pap or chap");
    }

    public AccessRequestMsg(String secret) {
        super(secret);
        code = getPacketCode() ;
    }

    @Override
    public int getPacketCode() {
        return PACKET_CODE;
    }

    @Override
    protected void parseAttributes(List<byte[]> attrBytesList) throws RadiusException {
        ChapChallengeAttr chapChallengeAttr = new ChapChallengeAttr();
        //判断认证类型时PAP还是CHAP，如果时CHAP将Chap-Challenge属性先解析出来
        for (byte[] attrBytes : attrBytesList) {
            int type = attrBytes[RadiusMsgAttr.INDEX_TYPE] & 0XFF;
            if (type == ChapPasswordAttr.ATTR_TYPE || type == ChapChallengeAttr.ATTR_TYPE) {
                setAuthProtocol(AUTH_CHAP);
            }
            if (type == ChapChallengeAttr.ATTR_TYPE) {
                chapChallengeAttr.parse(attrBytes);
                if (null == this.attributes) {
                    attributes = new LinkedList<>();
                }
                break;
            }
        }
        //进行所有属性的解析
        for (byte[] attrBytes : attrBytesList) {
            int type = attrBytes[RadiusMsgAttr.INDEX_TYPE] & 0XFF;
            if (!typeLegal(type, true)) {
                continue;
            }
            RadiusMsgAttr attr = null;
            if (type == ChapChallengeAttr.ATTR_TYPE) {
                attr = chapChallengeAttr;
            } else if (type == ChapPasswordAttr.ATTR_TYPE) {
                //解析Chap-Password属性
                attr = RadiusMsgAttrParser.parseChapPassworld(attrBytes, chapChallengeAttr);
                this.passwordAttr = attr;
            } else if (type == UserPasswordAttr.ATTR_TYPE) {
                //解析Pap-Password属性
                attr = RadiusMsgAttrParser.parsePapPassworld(attrBytes, secret, getAuthenticatorBytes(null));
                this.passwordAttr = attr;
            } else {
                attr = RadiusMsgAttrParser.parse(attrBytes);
                if (type == UserNameAttr.ATTR_TYPE) {
                    //判断是否时User-Name属性
                    this.userNameAttr = (UserNameAttr) attr;
                }
            }
            //加入属性列表中
            if (null != attr) {
                this.attributes.add(attr);
            }
        }
    }

    @Override
    protected byte[] getAuthenticatorBytes(byte[] byteWithoutAuthenticator) {
        if (null == authenticator) {
            byte[] tempByte = EncryptUtils.encryptMD5Bytes(UUID.randomUUID().toString());
            this.authenticator = tempByte;
        }
        return authenticator;
    }

    @Override
    protected List<byte[]> getAttributesBytesList() {
        List<byte[]> list = new LinkedList<>();
        if (null != attributes) {
            for (RadiusMsgAttr attr : attributes) {
                int type = attr.getAttrType();
                if (!typeLegal(type, true)) {
                    continue;
                }
                byte[] bytes = null;
                if (attr.getAttrType() == UserPasswordAttr.ATTR_TYPE) {
                    bytes = ((UserPasswordAttr) attr).getBytes(secret);
                } else {
                    bytes = attr.getBytes();
                }
                if (null != bytes) {
                    list.add(bytes);
                }
            }
        }
        return list;
    }

    @Override
    protected boolean typeLegal(int type, boolean print) {
        if ((type == FramedRoutingAttr.ATTR_TYPE) || (type == FilterIdAttr.ATTR_TYPE)
                || (type == LoginServiceAttr.ATTR_TYPE) || (type == LoginTcpPortAttr.ATTR_TYPE)
                || (type == ReplyMessageAttr.ATTR_TYPE) || (type == CallbackIdAttr.ATTR_TYPE)
                || (type == FramedRouteAttr.ATTR_TYPE) || (type == ClassAttr.ATTR_TYPE)
                || (type == SessionTimeoutAttr.ATTR_TYPE) || (type == IdleTimeoutAttr.ATTR_TYPE)

                || (type == TerminationActionAttr.ATTR_TYPE) || (type == FramedAppleTalkNetworkAttr.ATTR_TYPE)
                || (type == FramedAppleTalkZoneAttr.ATTR_TYPE)) {
            if (print) {
                System.out.println("Data can not be converted into this type of attribution , Type is inconsistent !!! " +
                        "Radius Access-Request packet required type can not be [ "
                        + FramedRoutingAttr.ATTR_TYPE + " , " + FilterIdAttr.ATTR_TYPE + " , "
                        + LoginServiceAttr.ATTR_TYPE + " , " + LoginTcpPortAttr.ATTR_TYPE + " , "
                        + ReplyMessageAttr.ATTR_TYPE + " , " + CallbackIdAttr.ATTR_TYPE + " , "
                        + FramedRouteAttr.ATTR_TYPE + " , " + ClassAttr.ATTR_TYPE + " , "
                        + SessionTimeoutAttr.ATTR_TYPE + " , " + IdleTimeoutAttr.ATTR_TYPE + " , "

                        + TerminationActionAttr.ATTR_TYPE + " , " + FramedAppleTalkNetworkAttr.ATTR_TYPE + " , "
                        + FramedAppleTalkZoneAttr.ATTR_TYPE
                        + " ]");
            }
            return false;
        }
        return true;
    }
}
